Skip to content

fix(mobile): recover keyboard composers after Android resume - #8212

Open
mrmg wants to merge 6 commits into
pingdotgg:mainfrom
mrmg:agent/fix-android-keyboard-focus
Open

mrmg wants to merge 6 commits into
pingdotgg:mainfrom
mrmg:agent/fix-android-keyboard-focus

Conversation

@mrmg

@mrmg mrmg commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Problem

On Android, task switching while the IME is dismissing can leave KeyboardStickyView with a stale animated height after resume, so the composer remains high on the screen after the keyboard closes.

Reproduction

Android keyboard composer remains elevated after task switching

Fix

Quarantine keyboard translation on Android resume and release it only after a fresh keyboard-show event or owned input focus. Apply the guard to the thread, new-task, terminal, and review sticky surfaces, with a pure lifecycle regression test.

Verification

  • vp test run apps/mobile/src/features/keyboard/androidKeyboardRecovery.test.ts apps/mobile/src/features/threads/pendingUserInputLayout.test.ts
  • vp run --filter @t3tools/mobile typecheck
  • Scoped vp fmt --check
  • Scoped vp lint --report-unused-disable-directives

Android emulator/device verification was not available in this environment.

Built with GPT-5.6-Luna in the Codex harness.


Note

Medium Risk
Touches native terminal events and keyboard layout across several high-traffic Android screens; incorrect quarantine timing could briefly mis-position composers or sticky toolbars, but changes are scoped to Android keyboard recovery with iOS paths largely unchanged.

Overview
Fixes Android composers and terminal chrome staying elevated after task-switching during IME dismiss by quarantining reliance on react-native-keyboard-controller visibility/height until the keyboard stream is known-good again.

Introduces a small recovery state machine (useAndroidKeyboardRecovery + helpers) that enters quarantined on app resume (and for Android surfaces mounted while already active) and returns to ready on keyboardWillShow or when an owned text field gains focus. Thread detail, new task, review comment composer, and the terminal route now gate KeyboardStickyView, bottom insets, and accessory visibility on isAndroidKeyboardAnimationUsable instead of raw keyboard visibility; thread detail drops its ad-hoc keyboardStateSuspect logic in favor of the shared hook.

Adds native onTerminalFocus on the T3 terminal view (iOS + Android) so focusing the hidden terminal EditText can release the quarantine; Android also emits focus when requestKeyboardFocus runs with retained focus and IME window insets show the keyboard is actually visible.

Reviewed by Cursor Bugbot for commit 370d829. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix stale keyboard composers after Android resume with recovery quarantine

  • Adds a shared Android keyboard-recovery state machine in androidKeyboardRecovery.ts and a useAndroidKeyboardRecovery hook that quarantines keyboard animation after app resume or active-state mounting, releasing on a fresh keyboard-show or owned-input-focus event
  • Adds a terminal-focus native event on both Android (T3TerminalView.kt) and iOS (T3TerminalView.swift), forwarded through NativeTerminalSurface.tsx, so terminal input focus can release the quarantine
  • Updates ThreadDetailScreen.tsx, NewTaskDraftScreen.tsx, ReviewCommentComposerSheet.tsx, and ThreadTerminalRouteScreen.tsx to gate sticky keyboard layouts and bottom insets on the shared usability predicate instead of raw keyboard visibility
  • Risk: the requestKeyboardFocus handler in T3TerminalView now checks window insets for IME visibility before dispatching focus; if insets are unavailable on a device, the focus event may not fire and the quarantine could persist until the next keyboard-show event

Macroscope summarized 370d829.

@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bd0574a3-7ade-44d2-85f1-4337a11d9d40

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 25, 2026
Comment thread apps/mobile/src/features/terminal/ThreadTerminalRouteScreen.tsx Outdated
Comment thread apps/mobile/src/features/review/ReviewCommentComposerSheet.tsx
Comment thread apps/mobile/src/features/keyboard/useAndroidKeyboardRecovery.ts
@macroscopeapp

macroscopeapp Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces cross-cutting Android keyboard recovery state and native focus events, changing resume, inset, sticky-composer, and terminal behavior across several existing mobile workflows. Its native-to-JS lifecycle coordination is broader than a small self-contained fix and warrants human review.

You can add or adjust custom eligibility rules. Learn more.

Comment thread apps/mobile/src/features/terminal/ThreadTerminalRouteScreen.tsx Outdated
@mrmg
mrmg force-pushed the agent/fix-android-keyboard-focus branch from 0e0c2cb to 185081b Compare September 4, 2026 13:25
Comment thread apps/mobile/src/features/terminal/ThreadTerminalRouteScreen.tsx
Comment thread apps/mobile/src/features/keyboard/useAndroidKeyboardRecovery.ts Outdated
mrmg added 2 commits September 4, 2026 14:40
A surface mounted while the app is active already starts quarantined via
the initial state, so the mount effect re-applying resume was redundant —
and when autoFocus released the guard before the effect ran, the effect
re-quarantined the surface with no future show event to lift it.
requestFocus on an already-focused EditText emits no focus callback, so a
Show keyboard press after an Android resume with retained IME focus never
reached onTerminalFocus and the surface stayed quarantined while the real
keyboard was up. Emit the focus event when focus was already retained.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 75b7258. Configure here.

The retained-focus emit also ran for canvas touches, so a post-resume
scroll could clear the recovery quarantine on a stale snapshot. Window
insets are ground truth: only synthesize the focus event when the IME is
genuinely visible.
Sowyu pushed a commit to Sowyu/t3pretzel that referenced this pull request Sep 15, 2026
Fixes reproduced on an Android emulator and from upstream reports.

Feed: Android stops drawing a text view past the GPU's maximum texture
height, so a long list rendered as one selectable Text lost its tail and
took seconds per frame to draw. Long lists now split into 40-item chunks.
Wide assistant markdown blocks keep a pinned width; the feed reserves
bottom padding.

Keyboard: the feed re-pins after keyboard transitions settle and when the
composer collapses; the back gesture collapses the composer; sticky
composers only follow the keyboard after a fresh show or real focus
(upstream pingdotgg#8212).

Terminal: hardware Enter no longer moves focus off the terminal; keyboards
that use deleteSurroundingText (FUTO) send Backspace; forward delete works.

Also: stream haptics no longer buzz every 320ms on Android and all haptics
use the system engine; thread settings apply on tap without Save; typed
pairing codes are normalized to the server format; non-git projects fall
back to the current checkout instead of a dead worktree default; user CA
certificates are trusted; Ctrl/Cmd+Enter sends from a hardware keyboard;
thread rename, project favicons in the filter, tablet sidebar toggle,
desktop-window density, route titles, Material You review colors, bottom
gesture-bar insets, and the composer placeholder clipping (upstream PRs
pingdotgg#11503, pingdotgg#11370, pingdotgg#11339, pingdotgg#8200, pingdotgg#8717, pingdotgg#11445, pingdotgg#6003, pingdotgg#5052, pingdotgg#8362, pingdotgg#10709,
pingdotgg#11611, pingdotgg#8800, adapted).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant